package dsf.eshop.goods.service.impl;

import dsf.eshop.goods.entity.Goods;
import dsf.eshop.goods.entity.GoodsType;
import dsf.eshop.goods.entity.vo.Image;
import dsf.eshop.goods.repository.GoodsRepository;
import dsf.eshop.goods.service.GoodsSevice;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.inject.Inject;
import java.util.List;
import java.util.Optional;

@Service
@CacheConfig(cacheNames = {"goods"})
public class GoodsServiceImpl implements GoodsSevice {


    @Inject
    GoodsRepository goodsRepository;

    @Cacheable(key = "'goods:listByPage:'+a0+a1")
    @Transactional(propagation = Propagation.SUPPORTS, isolation = Isolation.READ_COMMITTED, readOnly = true)
    @Override
    public List<Goods> listByPage(int page, int size) {

        PageRequest pageRequest = PageRequest.of(page, size);
        Page<Goods> all = goodsRepository.findAll(null, pageRequest);
        return all.getContent();
    }

    @Transactional(propagation = Propagation.SUPPORTS, isolation = Isolation.READ_COMMITTED, readOnly = true)
    @Override
    public List<Goods> listByPage(int page, int size, Sort.Direction direction, String... properties) {


        Goods goods = new Goods();
        goods.setName("th");

        PageRequest pageRequest = PageRequest.of(page, size, direction, properties);
        Example.of(goods, ExampleMatcher.matching().withStringMatcher(ExampleMatcher.StringMatcher.ENDING));
        Page<Goods> all = goodsRepository.findAll(null, pageRequest);
        return all.getContent();
    }


    @Transactional(propagation = Propagation.SUPPORTS, isolation = Isolation.READ_COMMITTED, readOnly = true)
    @Override
    public List<Goods> listByPage(Example example, int page, int size, Sort.Direction direction, String... properties) {
        return null;
    }

    @Transactional(propagation = Propagation.SUPPORTS, isolation = Isolation.READ_COMMITTED, readOnly = true)
    @Override
    public List<Goods> listByPage(Example<Goods> example, Pageable pageable) {

        Page<Goods> all = goodsRepository.findAll(example, pageable);
        return all.getContent();
    }

    @Cacheable(key = "'goods:detail:'+a0")
    @Override
    public Goods detail(Integer id) {

        Optional<Goods> goods = goodsRepository.findById(id);
        return goods.get();
    }

    /*
    * TODO 修改之后需要使相应缓存失效 list
    * */
    @CachePut(key = "'goods:detail:'+a0.id")
    @Transactional
    @Override
    public void save(Goods goods) {

        goodsRepository.save(goods);
    }

    /*
    * TODO 需要确保读到目标行之后 目标行不会被删除 否则save方法会添加 所以此时需要有 写锁
    * */
    @Transactional(isolation = Isolation.REPEATABLE_READ)
    @Override
    public void delete(Integer id) {

        Optional<Goods> goods = goodsRepository.findById(id);
        Goods goods1 = goods.get();
        goods1.setStatus(1);
        goodsRepository.save(goods1);
    }


    @Transactional
    public void postImages(int id, List<Image> images) {

        Goods goods = goodsRepository.getOne(id);
        goods.postImages(images);
        goodsRepository.save(goods);
    }

    @Transactional
    public void deleteImages(int id, List<Integer> ids) {

        Goods goods = goodsRepository.getOne(id);
        goods.deleteImages(ids);
    }

    /*
    * TODO return type , I need return BaseResult , can do it by AOP ?
    *
    * */
    public void putTypes(int id, List<GoodsType> goodsTypes) {

        Goods goods = goodsRepository.getOne(id);
        goods.putTypes(goodsTypes);
    }

    public void deleteTypes(int id, List<Integer> types) {

        Goods goods = goodsRepository.getOne(id);
        goods.deleteTypes(types);
    }

}
